Skip to content

Conversation

@bogwar
Copy link
Collaborator

@bogwar bogwar commented Apr 1, 2025

Real World Asset ledgers require several management APIs that would allow authorised entities to carry out ledger changes. This standard introduces four new blocktypes:

  • block type 123freezeaccount that records that a specific account was frozen by an authorised party
  • block type 123unfreezeaccount that records that a specific account was unfrozen by an authorised party
  • block type 123freezeprincipal that records that all of the accounts of a specific principal were frozen by an authorised party
  • block type 123unfreezeprincipal that records that all of the accounts of a specific principal were unfrozen by an authorised party

@bogwar bogwar changed the title Bw/icrc 123 ICRC-123: A standard for recording freezing and unfreezing of accounts and principals in ICRC ledgers Apr 2, 2025
@bogwar bogwar changed the title ICRC-123: A standard for recording freezing and unfreezing of accounts and principals in ICRC ledgers ICRC-123: ledger blocks for recording management actions -- freezing and unfreezing of accounts and principals Apr 4, 2025
@bogwar bogwar requested a review from Copilot April 7, 2025 12:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

ICRCs/ICRC-123/ICRC-123.md:3

  • [nitpick] Consider rewording to 'account freezing and unfreezing events' for clarity and consistency.
ICRC-123 introduces new block types for recording account and unfreezing events in ICRC-compliant ledgers.

@bogwar bogwar requested a review from Copilot April 7, 2025 13:59
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 1 out of 1 changed files in this pull request and generated no comments.

Comments suppressed due to low confidence (1)

ICRCs/ICRC-123/ICRC-123.md:3

  • [nitpick] Consider rephrasing 'recording account and unfreezing events' to 'recording account freeze and unfreeze events' for clarity and consistency with the rest of the document.
ICRC-123 introduces new block types for recording account and unfreezing events in ICRC-compliant ledgers.


### Ledger Enforcement Rules

- A ledger **MUST reject** any transfer transaction (`icrc1_transfer` or `icrc2_transfer_from`) where the **sender or recipient account is currently RESTRICTED**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the spender of an icrc2_transfer_from transaction?

Can/should we say anything about the errors that should be returned in this case? TransferError in ICRC-1 and TransferFromError in ICRC-2 don't seem to specify any variants that would be a good fit here - can we recommend some specific GenericError error code and/or message?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the first question: thanks for bringing it up. The current version should preclude it.

For the second: I wouldn't introduce a code right now but a reasonable message ("Sending account/receiving account is frozen") may be good. Open to suggestions.


### Querying Freeze Status

Ledgers implementing this standard SHOULD expose a query interface (e.g., `is_account_restricted(account): bool`) that returns whether an account is currently RESTRICTED according to the rules defined in "Account Status". This serves as a convenience layer and does not replace auditing based on block history.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we clearly define the query interface to be used? what's the benefit of leaving this up to the implementer?

I think the ecosystem would benefit of having query interfaces clearly defined.

Copy link
Member

@marc0olo marc0olo May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean we could leave it up to the implementer to decide whether to expose such function or not. but if they decide to implement it, it would be good to have a common/reusable function name for that.

clients might need to implement some error handling though if this function is not present. (or we add an additional query function to check whether this is function is available or not 🤣 )

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this choice is in line with the idea that in this standard we only define the block formats and a standarised interface can then go into a second standard

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in any way it would be good to be consistent on this matter also for ICRC-124 where querying the ledger status is not mentioned specifically at this point.

maybe we should mention again that the interface definition is just a suggestion and might be standardized in another ICRC

Comment on lines 116 to 134
vec {
    // ... other supported types like ICRC-1 ...
    variant { Record = vec {
        record { "btype"; variant { Text = "123freezeaccount" }};
        record { "url"; variant { Text = "[https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md)" }}; // Placeholder URL
    }};
    variant { Record = vec {
        record { "btype"; variant { Text = "123unfreezeaccount" }};
        record { "url"; variant { Text = "[https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md)" }}; // Placeholder URL
    }};
    variant { Record = vec {
        record { "btype"; variant { Text = "123freezeprincipal" }};
        record { "url"; variant { Text = "[https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md)" }}; // Placeholder URL
    }};
    variant { Record = vec {
        record { "btype"; variant { Text = "123unfreezeprincipal" }};
        record { "url"; variant { Text = "[https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md](https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-123.md)" }}; // Placeholder URL
    }};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove placeholder URL comment and check the url content (currently a markdown link)

Copy link
Member

@marc0olo marc0olo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some comments


This "latest-action-wins" rule implies:
- A freeze of an account (`123freezeaccount`) can be lifted by a later unfreeze of the same account (`123unfreezeaccount`) or by a later unfreeze of the owning principal (`123unfreezeprincipal`).
- A freeze of a principal (`123freezeprincipal`) can be lifted by a later unfreeze of that principal (`123unfreezeprincipal`). It also implicitly unfreezes all accounts owned by that principal unless a more recent, specific `123freezeaccount` block targets one of those accounts.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A freeze of a principal (`123freezeprincipal`) can be lifted by a later unfreeze of that principal (`123unfreezeprincipal`). It also implicitly unfreezes all accounts owned by that principal unless a more recent, specific `123freezeaccount` block targets one of those accounts.
- A freeze of a principal (`123freezeprincipal`) can be lifted by a later unfreeze of that principal (`123unfreezeprincipal`). It also implicitly unfreezes all accounts owned by that principal unless a more recent, specific `123freezeaccount` block targets one of those accounts. Furthermore a freeze of specific accounts of this principal can be lifted by a later `123unfreezeaccount`.

- A freeze of an account (`123freezeaccount`) can be lifted by a later unfreeze of the same account (`123unfreezeaccount`) or by a later unfreeze of the owning principal (`123unfreezeprincipal`).
- A freeze of a principal (`123freezeprincipal`) can be lifted by a later unfreeze of that principal (`123unfreezeprincipal`). It also implicitly unfreezes all accounts owned by that principal unless a more recent, specific `123freezeaccount` block targets one of those accounts.

### Ledger Enforcement Rules
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rules for ICRC122 methods are missing

- A ledger **MUST reject** any `icrc1_transfer` or `icrc2_transfer_from` transaction where the **sender** account (the `from` account in the operation) is currently RESTRICTED.
- The ledger **MAY**, according to its policy, also reject `icrc1_transfer` or `icrc2_transfer_from` transactions if the **recipient** account (the `to` account in the operation) is RESTRICTED, or it MAY allow incoming funds to a RESTRICTED recipient.
- **ICRC-2 Operations:**
- **`icrc2_approve` (Granting Approval):** If an account is RESTRICTED, its owner **MUST NOT** be able to authorize an `icrc2_approve` transaction where this restricted account is the one granting the approval (i.e., the `account` argument in `icrc2_approve` which specifies the owner of the funds being approved for spending).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **`icrc2_approve` (Granting Approval):** If an account is RESTRICTED, its owner **MUST NOT** be able to authorize an `icrc2_approve` transaction where this restricted account is the one granting the approval (i.e., the `account` argument in `icrc2_approve` which specifies the owner of the funds being approved for spending).
- **`icrc2_approve` (Granting Approval):** If an account is RESTRICTED, its owner **MUST NOT** be able to authorize an `icrc2_approve` transaction where this restricted account is the one granting the approval (i.e., the `caller` in combination with the `from_subaccount` argument in `icrc2_approve` which together specify the `from` account that is being approved for spending).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants